/*
既然我们拿到了类的定义，那是否可以通过Class对象来创建对象、调用方法、修改变量呢？当然可以。
首先我们先探讨一下如何创建一个类的对象
 */
package Class_Object;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

public class CreateClassObject {
    public static void main(String[] args) throws InstantiationException, IllegalAccessException, NoSuchMethodException, InvocationTargetException {
        /*
        解释下throws后面的几个异常
        当类默认的无参public构造方法被带参构造覆盖时，会出现InstantiationException异常，因为newInstance()只适用于无参构造
        当类默认的无参public构造方式不是public权限是，会出现IllegalAccessException异常，表示我们没有访问构造方法权限
        当使用getConstructor()时，有可能找不到方法，会抛出找不到方法的异常，要用NoSuchMethodException
        InvocationTargetException（反射异常），当被调用的方法的内部抛出了异常而没有被捕获时，将由此异常接收
        上面4种异常可以统一由一个ReflectiveOperationException反射异常代替
         */
        Class<Student> clazz = Student.class;  //获取Class对象
        Student student = clazz.newInstance();  //使用Class类对象，使用newInstance()创建实例对象。
        // newInstance()只支持无参public构造方法的类。
        student.test();

        //且newInstance()在jdk1.9降级了，不建议使用了,推荐通过获取构造器getConstructor()来实例化对象
        Class<Student2> clazz2 = Student2.class;
        Student2 student2 = clazz2.getConstructor(String.class).newInstance("你二大爷"); //还可以使用getConstructors获取所有构造方法，返回的是数组
        student2.test();


        //那如果使用获取构造器的时候，构造方法是private时，怎么办(通过反射来创建对象）
        Class<Student3> clszz3 = Student3.class;
        Constructor<Student3> constructor = clszz3.getDeclaredConstructor(String.class);  //获取已声明的构造方法，无视权限
        constructor.setAccessible(true);  //修改构造方法访问权限，即使构造方式是private，也可以访问，这就是反射的特点，无视权限修饰符访问类的内容
        Student3 student3 = constructor.newInstance("你三大爷");  //使用构造方法来创建类对象实例
        student3.test();
        //https://www.cnblogs.com/jiangyi-uestc/p/5686264.html
        /*
        getDeclaredConstructor(Class<?>... parameterTypes)
        这个方法会返回制定参数类型的所有构造器，包括public的和非public的，当然也包括private的。
        getDeclaredConstructors()的返回结果就没有参数类型的过滤了。

        再来看getConstructor(Class<?>... parameterTypes)
        这个方法返回的是上面那个方法返回结果的子集，只返回制定参数类型访问权限是public的构造器。
        getConstructors()的返回结果同样也没有参数类型的过滤。
         */


}
    static class Student{  //Student类，使用默认的构造方法，默认无参public构造
        public void test(){
            System.out.println("萨日朗");
        }
    }

    static class Student2{
        public Student2(String str){}
        public void test(){
            System.out.println("萨尔朗");
        }
    }

    static class Student3{
        private Student3(String str){}
        public void test(){
            System.out.println("萨三朗");
        }
    }


}
